home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
- * All rights reserved. The file named COPYRIGHT specifies the terms
- * and conditions for redistribution.
- */
-
- static char RCSid[] = "$Id: siosup.c,v 1.5 1995/09/10 18:35:09 chuck Exp $" ;
-
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-
- #include "impl.h"
- #include "sio.h"
-
- #ifdef EVENTS
- #include "events.h"
- #endif
-
- #if defined(BSD) || defined(linux)
- PRIVATE void terminate() ;
- PRIVATE status_e setup_read_buffer( register __sio_id_t *idp ,
- unsigned buf_size );
- #endif
- char *malloc() ;
- char *realloc() ;
-
-
- static __sio_descriptor_t static_descriptor_array[ N_SIO_DESCRIPTORS ] ;
- static int n_descriptors = N_SIO_DESCRIPTORS ;
- __sio_descriptor_t *__sio_descriptors = static_descriptor_array ;
-
- #ifdef EVENTS
- static events_s static___sio_events[ N_SIO_DESCRIPTORS ] ;
- events_s *__sio_events = static___sio_events ;
- #endif
-
-
- /*
- * Code for finalization
- */
- #ifdef HAS_FINALIZATION_FUNCTION
- static int finalizer_installed ;
-
- SIO_DEFINE_FIN( sio_cleanup )
- {
- (void) Sflush( SIO_FLUSH_ALL ) ;
- }
- #endif /* HAS_FINALIZATION_FUNCTION */
-
-
-
- #ifdef HAS_MMAP
-
- #define CHAR_NULL ((char *)0)
-
- /*
- * PAGES_MAPPED gives the size of each map unit in pages
- */
- #define PAGES_MAPPED 2
-
- static size_t map_unit_size = 0 ; /* bytes */
- static size_t page_size = 0 ; /* bytes */
-
- static mapd_s static_mapd_array[ N_SIO_DESCRIPTORS ] ;
- static mapd_s *mmap_descriptors = static_mapd_array ;
-
- #define MDP( fd ) ( mmap_descriptors + (fd) )
-
-
- /*
- * NOTES ON MEMORY MAPPING:
- *
- * 1. Memory mapping works only for file descriptors opened for input
- * 2. Mapping an object to a part of the address space where another
- * object is mapped will cause the old mapping to disappear (i.e. mmap
- * will not fail)
- *
- * Memory mapping interface:
- * SIO_MMAP : maps a file into a portion of the address space.
- * SIO_MUNMAP: unmap a portion of the address space
- * SIO_MNEED: indicate to the OS that we will need a portion of
- * our address space.
- *
- * The map_unit_size variable defines how much of the file is mapped at
- * a time. It is a multiple of the operating system page size. It is
- * not less than SIO_BUFFER_SIZE unless SIO_BUFFER_SIZE is not a
- * multiple of the page size (so the SIO_BUFFER_SIZE overrides
- * PAGES_MAPPED).
- *
- * NOTE: All memory mapping code is in this file only
- */
-
-
- /*
- * Macros used by the memory mapping code
- */
- #define FIRST_TIME( dp ) ( dp->buf == NULL )
- #define FATAL_ERROR( msg ) perror( msg ), exit( 1 )
-
- /*
- * Functions to support memory mapping:
- *
- * try_memory_mapping
- * buffer_setup
- * __sio_switch
- * initial_map
- * map_unit
- */
-
- /*
- * try_memory_mapping attempts to setup the specified descriptor
- * for memory mapping.
- * It returns FAILURE if it fails and SUCCESS if it is successful.
- * If HAS_MMAP is not defined, the function is defined to be FAILURE.
- *
- * Sets fields:
- * memory_mapped: TRUE or FALSE
- *
- * Also sets the following fields if memory_mapped is TRUE:
- * file_offset, file_size, buffer_size
- *
- */
- PRIVATE status_e try_memory_mapping( fd, idp, stp )
- int fd ;
- register __sio_id_t *idp ;
- struct stat *stp ;
- {
- int access ;
-
- #ifdef EVENTS
- EVENT( fd, EV_TRY_MEMORY_MAPPING ) ;
- #endif
-
- /*
- * Do not try memory mapping if:
- * 1) The file is not a regular file
- * 2) The file is a regular file but has zero-length
- * 3) The file pointer is not positioned at the beginning of the file
- * 4) The fcntl to obtain the file descriptor flags fails
- * 5) The access mode is not O_RDONLY or O_RDWR
- *
- * The operations are done in this order to avoid the system calls
- * if possible.
- */
- if ( ( ( stp->st_mode & S_IFMT ) != S_IFREG ) ||
- ( stp->st_size == 0 ) ||
- ( lseek( fd, (long)0, 1 ) != 0 ) ||
- ( ( access = fcntl( fd, F_GETFL, 0 ) ) == -1 ) ||
- ( ( access &= 0x3 ) != O_RDONLY && access != O_RDWR ) )
- {
- idp->memory_mapped = FALSE ;
- return( FAILURE ) ;
- }
-
- /*
- * Determine page_size and map_unit_size.
- * Note that the code works even if PAGES_MAPPED is 0.
- */
- if ( page_size == 0 )
- {
- page_size = getpagesize() ;
- map_unit_size = page_size * PAGES_MAPPED ;
- if ( map_unit_size < SIO_BUFFER_SIZE )
- if ( map_unit_size > 0 && SIO_BUFFER_SIZE % map_unit_size == 0 )
- map_unit_size = SIO_BUFFER_SIZE ;
- else
- map_unit_size = page_size ;
- }
-
- MDP(fd)->file_offset = 0 ;
- MDP(fd)->file_size = stp->st_size ;
- idp->buffer_size = map_unit_size ;
- idp->buf = CHAR_NULL ;
- idp->memory_mapped = TRUE ;
-
- return( SUCCESS ) ;
- }
-
-
- /*
- * Copy the current_unit to the primary buffer
- *
- * Sets fields: start, end, nextb
- * Also sets the file pointer
- */
- PRIVATE void buffer_setup( idp, fd, mu_cur, mu_next )
- __sio_id_t *idp ;
- int fd ;
- struct map_unit *mu_cur ;
- struct map_unit *mu_next ;
- {
- off_t new_offset ;
-
- sio_memcopy( mu_cur->addr, idp->buf, mu_cur->valid_bytes ) ;
- idp->start = idp->buf ;
- idp->end = idp->buf + mu_cur->valid_bytes ;
- idp->nextb = idp->buf + ( idp->nextb - mu_cur->addr ) ;
-
- if ( mu_next->addr != CHAR_NULL )
- new_offset = MDP(fd)->file_offset - mu_next->valid_bytes ;
- else
- new_offset = MDP(fd)->file_offset ;
- (void) lseek( fd, new_offset, 0 ) ;
- }
-
-
- /*
- * Switch from memory mapping to buffered I/O
- * If any mapping has occured, then the current unit is
- * copied into the buffer that is allocated.
- * Any data in the next unit is ignored.
- * We rely on idp->buf to identify the current unit (so it
- * better be equal to the address of one of the units).
- *
- * Sets fields:
- * start, end, nextb
- */
- status_e __sio_switch( idp, fd )
- register __sio_id_t *idp ;
- int fd ;
- {
- register mapd_s *mdp = MDP( fd ) ;
- struct map_unit *mu_cur, *mu_next ;
- unsigned buffer_size = idp->buffer_size ;
- char *buf_addr = idp->buf ;
- int first_time = FIRST_TIME( idp ) ;
- void buffer_setup() ;
- status_e setup_read_buffer() ;
-
- #ifdef EVENTS
- EVENT( fd, EV_SIO_SWITCH ) ;
- #endif
-
- /*
- * Initialize stream for buffering
- */
- if ( setup_read_buffer( idp, buffer_size ) == FAILURE )
- return( FAILURE ) ;
-
- if ( ! first_time )
- {
- /*
- * Find current, next unit
- */
- if ( buf_addr == mdp->first_unit.addr )
- {
- mu_cur = &mdp->first_unit ;
- mu_next = &mdp->second_unit ;
- }
- else
- {
- mu_cur = &mdp->second_unit ;
- mu_next = &mdp->first_unit ;
- }
-
- buffer_setup( idp, fd, mu_cur, mu_next ) ;
- /*
- * Destroy all mappings
- */
- (void) SIO_MUNMAP( mu_cur->addr, mu_cur->mapped_bytes ) ;
- if ( mu_next->addr != NULL )
- (void) SIO_MUNMAP( mu_next->addr, mu_next->mapped_bytes ) ;
- }
- else
- idp->start = idp->end = idp->nextb = idp->buf ;
-
- idp->memory_mapped = FALSE ;
- return( SUCCESS ) ;
- }
-
-
- /*
- * initial_map does the first memory map on the file descriptor.
- * It attempts to map both units.
- * The mapping always starts at file offset 0.
- *
- * SETS FIELDS:
- * first_unit.*, second_unit.*
- * file_offset
- *
- * Returns:
- * number of bytes mapped in first_unit
- * or
- * 0 to indicate that mmap failed.
- */
- PRIVATE int initial_map( mdp, fd )
- register mapd_s *mdp ;
- int fd ;
- {
- register caddr_t addr ;
- register size_t requested_length = 2 * map_unit_size ;
- register size_t mapped_length = MIN( mdp->file_size, requested_length ) ;
- size_t bytes_left ;
- register size_t bytes_in_unit ;
-
- #ifdef EVENTS
- EVENT( fd, EV_INITIAL_MAP ) ;
- #endif
-
- addr = SIO_MMAP( CHAR_NULL, mapped_length, fd, 0 ) ;
- if ( (int) addr == -1 )
- return( 0 ) ;
-
- SIO_MNEED( addr, mapped_length ) ;
-
- /*
- * Map as much as possible in the first unit
- */
- bytes_in_unit = MIN( mapped_length, map_unit_size ) ;
- mdp->first_unit.addr = addr ;
- mdp->first_unit.mapped_bytes = bytes_in_unit ;
- mdp->first_unit.valid_bytes = bytes_in_unit ;
-
- /*
- * If there is more, map it in the second unit.
- */
- bytes_left = mapped_length - bytes_in_unit ;
- if ( bytes_left > 0 )
- {
- mdp->second_unit.addr = addr + bytes_in_unit ;
- mdp->second_unit.mapped_bytes = bytes_left ;
- mdp->second_unit.valid_bytes = bytes_left ;
- }
- else
- mdp->second_unit.addr = CHAR_NULL ;
-
- mdp->file_offset = mapped_length ;
-
- return( mdp->first_unit.valid_bytes ) ;
- }
-
-
- /*
- * ALGORITHM:
- *
- * if ( there are more bytes in the file )
- * {
- * map them at the given unit
- * update offset
- * issue SIO_MNEED()
- * }
- * else
- * unmap the unit
- */
- PRIVATE status_e map_unit( mdp, fd, mup )
- register mapd_s *mdp ;
- int fd ;
- register struct map_unit *mup ;
- {
- register size_t bytes_left = mdp->file_size - mdp->file_offset ;
- register size_t bytes_to_map = MIN( bytes_left, map_unit_size ) ;
-
- #ifdef EVENTS
- EVENT( fd, EV_MAP_UNIT ) ;
- #endif
-
- if ( bytes_to_map > 0 )
- {
- if ( (int) SIO_MMAP( mup->addr, bytes_to_map,
- fd, mdp->file_offset ) == -1 )
- return( FAILURE ) ; /* XXX: need to do more ? */
-
- mup->valid_bytes = bytes_to_map ;
- ASSERT( mup->valid_bytes <= mup->mapped_bytes ) ;
- mdp->file_offset += bytes_to_map ;
- SIO_MNEED( mup->addr, mup->valid_bytes ) ;
- }
- else
- {
- (void) SIO_MUNMAP( mup->addr, mup->mapped_bytes ) ;
- mup->addr = CHAR_NULL ;
- }
- return( SUCCESS ) ;
- }
-
- #else
-
- #define try_memory_mapping( x, y, z ) FAILURE
-
- #endif /* HAS_MMAP */
-
-
- PRIVATE status_e setup_read_buffer( idp, buf_size )
- register __sio_id_t *idp ;
- unsigned buf_size ;
- {
- register char *buf ;
-
- /*
- * First allocate space for 2 buffers: primary and auxiliary
- */
- buf = malloc( buf_size * 2 ) ;
- if ( buf == NULL )
- return( FAILURE ) ;
-
- /*
- * The descriptor buf field should point to the start of the main buffer
- */
- idp->buf = buf + buf_size ;
- idp->buffer_size = buf_size ;
- return( SUCCESS ) ;
- }
-
-
- PRIVATE status_e init_input_stream( idp, fd, stp )
- register __sio_id_t *idp ;
- int fd ;
- struct stat *stp ;
- {
- #ifdef EVENTS
- EVENT( fd, EV_INIT_INPUT_STREAM ) ;
- #endif
-
- /*
- * First initialize the fields relevant to buffering: buf, buffer_size
- */
- if ( try_memory_mapping( fd, idp, stp ) == FAILURE )
- {
- /*
- * Try to use normal buffering
- */
- unsigned buf_size = (unsigned)
- ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
-
- if ( setup_read_buffer( idp, buf_size ) == FAILURE )
- return( FAILURE ) ;
- }
-
- /*
- * Initialize remaining descriptor fields
- */
- idp->max_line_length = 2 * idp->buffer_size - 1 ;
- idp->start = idp->end = idp->nextb = idp->buf ;
- idp->tied_fd = SIO_NO_TIED_FD ;
-
- return( SUCCESS ) ;
- }
-
-
- PRIVATE status_e init_output_stream( odp, fd, stp )
- register __sio_od_t *odp ;
- int fd ;
- struct stat *stp ;
- {
- register unsigned buf_size ;
- register char *buf ;
-
- #ifdef EVENTS
- EVENT( fd, EV_INIT_OUTPUT_STREAM ) ;
- #endif
-
- buf_size = (unsigned)
- ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
- buf = malloc( buf_size ) ;
- if ( buf == NULL )
- return( FAILURE ) ;
-
- /*
- * Initialize buffering fields
- */
- odp->buf = buf ;
- odp->buffer_size = buf_size ;
- odp->buf_end = odp->buf + buf_size ;
-
- /*
- * Initialize remaining fields
- */
- odp->start = odp->nextb = odp->buf ;
- if ( isatty( fd ) )
- odp->buftype = SIO_LINEBUF ;
-
- if ( fd == 2 )
- odp->buftype = SIO_NOBUF ;
-
- return( SUCCESS ) ;
- }
-
-
- #ifndef HAS_ISATTY
-
- #ifdef HAS_SYSVTTY
-
- #include <termio.h>
-
- PRIVATE int isatty( fd )
- int fd ;
- {
- struct termio t ;
-
- if ( ioctl( fd, TCGETA, &t ) == -1 && errno == ENOTTY )
- return( FALSE ) ;
- else
- return( TRUE ) ;
- }
- #endif /* HAS_SYSVTTY */
-
- #ifdef HAS_BSDTTY
-
- #include <sgtty.h>
-
- PRIVATE int isatty( fd )
- int fd ;
- {
- struct sgttyb s ;
-
- if ( ioctl( fd, TIOCGETP, &s ) == -1 && errno == ENOTTY )
- return( FALSE ) ;
- else
- return( TRUE ) ;
- }
- #endif /* HAS_BSDTTY */
-
- #endif /* ! HAS_ISATTY */
-
-
- /*
- * Initialize stream I/O for a file descriptor.
- *
- * Arguments:
- * fd: file descriptor
- * dp: descriptor pointer
- * stream_type: either __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
- *
- * Returns
- * 0 if successful
- * SIO_ERR if the file descriptor is not valid (sets errno)
- * exits if stream_type is not __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
- */
- int __sio_init( dp, fd, stream_type )
- register __sio_descriptor_t *dp ;
- int fd ;
- enum __sio_stream stream_type ;
- {
- struct stat st ;
- #if !defined(linux) && !defined(BSD)
- void terminate() ;
- #endif
-
- #ifdef EVENTS
- EVENT( fd, EV_SIO_INIT ) ;
- #endif
-
- if ( fstat( fd, &st ) == -1 )
- return( SIO_ERR ) ;
-
- switch ( stream_type )
- {
- case __SIO_INPUT_STREAM:
- if ( init_input_stream( IDP( dp ), fd, &st ) == FAILURE )
- return( SIO_ERR ) ;
- break ;
-
- case __SIO_OUTPUT_STREAM:
- if ( init_output_stream( ODP( dp ), fd, &st ) == FAILURE )
- return( SIO_ERR ) ;
- break ;
-
- default:
- terminate( "SIO __sio_init: bad stream type (internal error).\n" ) ;
- /* NOTREACHED */
- }
- dp->stream_type = stream_type ;
- dp->initialized = TRUE ;
-
- #ifdef HAS_FINALIZATION_FUNCTION
- if ( ! finalizer_installed )
- {
- if ( ! SIO_FINALIZE( sio_cleanup ) )
- {
- char *s = "SIO __sio_init: finalizer installation failed\n" ;
-
- (void) write( 2, s, strlen( s ) ) ;
- }
- else
- finalizer_installed = TRUE ;
- }
- #endif /* HAS_FINALIZATION_FUNCTION */
-
- return( 0 ) ;
- }
-
-
- /*
- * __sio_writef writes the data in the buffer to the file descriptor.
- *
- * It tries to write as much data as possible until either all data
- * are written or an error occurs. EINTR is the only error that is
- * ignored.
- * In case an error occurs but some data were written, that number
- * is returned instead of SIO_ERR.
- *
- * Fields modified:
- * When successful: start, nextb
- * When not successful: start
- *
- * Return value:
- * Number of bytes written
- * SIO_ERR, if write(2) fails and no data were written
- */
- int __sio_writef( odp, fd )
- register __sio_od_t *odp ;
- int fd ;
- {
- register int b_in_buffer ;
- register int cc_total = 0 ;
-
- #ifdef EVENTS
- EVENT( fd, EV_SIO_WRITEF ) ;
- #endif
-
- /*
- * Make sure we don't exceed the buffer limits
- * Maybe we should log this ? XXX
- */
- if ( odp->nextb > odp->buf_end )
- odp->nextb = odp->buf_end ;
-
- b_in_buffer = odp->nextb - odp->start ;
-
- if ( b_in_buffer == 0 )
- return( 0 ) ;
-
- for ( ;; )
- {
- register int cc ;
-
- cc = write( fd, odp->start, b_in_buffer ) ;
- if ( cc == b_in_buffer )
- {
- odp->start = odp->nextb = odp->buf ;
- cc_total += cc ;
- break ;
- }
- else if ( cc == -1 )
- {
- if ( errno == EINTR )
- continue ;
- else
- /*
- * If some bytes were written, return that number, otherwise
- * return SIO_ERR
- */
- return( ( cc_total != 0 ) ? cc_total : SIO_ERR ) ;
- }
- else /* some bytes were written */
- {
- odp->start += cc ; /* advance start of buffer */
- b_in_buffer -= cc ; /* decrease number bytes left in buffer */
- cc_total += cc ; /* count the bytes that were written */
- }
- }
- return( cc_total ) ;
- }
-
-
- /*
- * __sio_readf reads data from the file descriptor into the buffer.
- * Unlike __sio_writef it does NOT try to read as much data as will fit
- * in the buffer. It ignores EINTR.
- *
- * Returns: # of bytes read or SIO_ERR
- *
- * Fields set:
- * If it does not return SIO_ERR, it sets start, nextb, end
- * If it returns SIO_ERR, it does not change anything
- */
- int __sio_readf( idp, fd )
- register __sio_id_t *idp ;
- int fd ;
- {
- register int cc ;
-
- #ifdef EVENTS
- EVENT( fd, EV_SIO_READF ) ;
- #endif
-
- /*
- * First check for a tied fd and flush the stream if necessary
- *
- * XXX the return value of __sio_writef is not checked.
- * Is that right ?
- */
- if ( idp->tied_fd != SIO_NO_TIED_FD )
- (void) __sio_writef( &__SIO_OD( idp->tied_fd ), idp->tied_fd ) ;
-
- #ifdef HAS_MMAP
- if ( idp->memory_mapped )
- {
- register mapd_s *mdp = MDP( fd ) ;
-
- /*
- * The functions initial_map and map_unit may fail.
- * In either case, we switch to buffered I/O.
- * If initial_map fails, we have read no data, so we
- * should perform a read(2).
- * If map_unit fails (for the next unit), we still have
- * the data in the current unit, so we can return.
- */
- if ( FIRST_TIME( idp ) )
- {
- cc = initial_map( mdp, fd ) ;
- if ( cc > 0 )
- idp->buf = mdp->first_unit.addr ;
- else
- {
- if ( __sio_switch( idp, fd ) == FAILURE )
- return( SIO_ERR ) ;
- cc = -1 ;
- }
- }
- else
- {
- register struct map_unit *mu_cur, *mu_next ;
-
- if ( idp->buf == mdp->first_unit.addr )
- {
- mu_cur = &mdp->first_unit ;
- mu_next = &mdp->second_unit ;
- }
- else
- {
- mu_cur = &mdp->second_unit ;
- mu_next = &mdp->first_unit ;
- }
-
- if ( mu_next->addr != NULL )
- {
- idp->buf = mu_next->addr ;
- cc = mu_next->valid_bytes ;
- /*
- * XXX: Here we may return SIO_ERR even though there
- * are data in the current unit because the switch
- * fails (possibly because malloc failed).
- */
- if ( map_unit( mdp, fd, mu_cur ) == FAILURE &&
- __sio_switch( idp, fd ) == FAILURE )
- return( SIO_ERR ) ;
- }
- else
- cc = 0 ;
- }
- if ( cc >= 0 )
- {
- idp->end = idp->buf + cc ;
- idp->start = idp->nextb = idp->buf ;
- return( cc ) ;
- }
- }
- #endif /* HAS_MMAP */
-
- for ( ;; )
- {
- cc = read( fd, idp->buf, (int) idp->buffer_size ) ;
- if ( cc == -1 )
- if ( errno == EINTR )
- continue ;
- else
- return( SIO_ERR ) ;
- else
- break ;
- }
-
- idp->end = idp->buf + cc ;
- idp->start = idp->nextb = idp->buf ;
- return( cc ) ;
- }
-
-
- /*
- * __sio_extend_buffer is used by Srdline to extend the buffer
- * If successful, it returns the number of bytes that have been read.
- * If it fails (because of end-of-file or I/O error), it returns 0 or -1.
- *
- * Fields modified:
- * idp->start points to the start of the buffer area (which is in the
- * auxiliary buffer)
- * Also, if successful, idp->nextb is set to idp->buf, idp->end is modified.
- */
- int __sio_extend_buffer( idp, fd, b_left )
- register __sio_id_t *idp ;
- int fd ;
- register int b_left ;
- {
- register int b_read ;
-
- #ifdef EVENTS
- EVENT( fd, EV_SIO_EXTEND_BUFFER ) ;
- #endif
-
- /*
- * copy to auxiliary buffer
- */
- if ( b_left )
- sio_memcopy( idp->nextb, idp->buf - b_left, b_left ) ;
- b_read = __sio_readf( idp, fd ) ;
- idp->start = idp->buf - b_left ;
- return( b_read ) ;
- }
-
-
- /*
- * __sio_more tries to read more data from the given file descriptor iff
- * there is free space in the buffer.
- * __sio_more is used only by Srdline and only AFTER __sio_extend_buffer
- * has been called. This implies that
- * a) this is not a memory mapped file
- * b) __sio_readf has been called (so we don't need to check for tied fd's
- *
- * Fields modified (only if successful):
- * idp->end
- *
- * Return value: the number of bytes read.
- */
- int __sio_more( idp, fd )
- register __sio_id_t *idp ;
- int fd ;
- {
- register int b_left = &idp->buf[ idp->buffer_size ] - idp->end ;
- register int cc ;
-
- #ifdef EVENTS
- EVENT( fd, EV_SIO_MORE ) ;
- #endif
-
- if ( b_left <= 0 )
- return( 0 ) ;
-
- for ( ;; )
- {
- cc = read( fd, idp->end, b_left ) ;
- if ( cc >= 0 )
- {
- idp->end += cc ;
- return( cc ) ;
- }
- else
- if ( errno == EINTR )
- continue ;
- else
- return( SIO_ERR ) ;
- }
- }
-
-
- /*
- * Finalize a buffer by unmapping the file or freeing the malloc'ed memory
- */
- int Sdone( fd )
- int fd ;
- {
- register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
-
- #ifdef EVENTS
- EVENT( fd, EV_SDONE ) ;
- #endif
-
- if ( ! DESCRIPTOR_INITIALIZED( dp ) )
- {
- errno = EBADF ;
- return( SIO_ERR ) ;
- }
-
- switch ( dp->stream_type )
- {
- case __SIO_INPUT_STREAM:
- {
- register __sio_id_t *idp = IDP( dp ) ;
-
- #ifdef HAS_MMAP
- if ( idp->memory_mapped )
- {
- register mapd_s *mdp = MDP( fd ) ;
-
- if ( mdp->first_unit.addr != CHAR_NULL )
- (void) SIO_MUNMAP( mdp->first_unit.addr,
- mdp->first_unit.mapped_bytes ) ;
- if ( mdp->second_unit.addr != CHAR_NULL )
- (void) SIO_MUNMAP( mdp->second_unit.addr,
- mdp->second_unit.mapped_bytes ) ;
- idp->memory_mapped = FALSE ;
- }
- else
- #endif /* HAS_MMAP */
- free( idp->buf - idp->buffer_size ) ;
- idp->nextb = idp->end = NULL ;
- }
- break ;
-
- case __SIO_OUTPUT_STREAM:
- {
- register __sio_od_t *odp = ODP( dp ) ;
-
- if ( Sflush( fd ) == SIO_ERR )
- return( SIO_ERR ) ;
- free( odp->buf ) ;
- odp->nextb = odp->buf_end = NULL ;
- }
- break ;
-
- default:
- terminate( "SIO Sdone: bad stream type\n" ) ;
- }
-
- dp->initialized = FALSE ;
- return( 0 ) ;
- }
-
-
- PRIVATE char *expand( area, old_size, new_size, is_static )
- char *area ;
- unsigned old_size, new_size ;
- int is_static ;
- {
- char *new_area ;
-
- if ( is_static )
- {
- if ( ( new_area = malloc( new_size ) ) == NULL )
- return( NULL ) ;
- sio_memcopy( area, new_area, old_size ) ;
- }
- else
- if ( ( new_area = realloc( area, new_size ) ) == NULL )
- return( NULL ) ;
- return( new_area ) ;
- }
-
-
- #include <sys/time.h>
- #include <sys/resource.h>
-
- PRIVATE int get_fd_limit()
- {
- #ifdef RLIMIT_NOFILE
-
- struct rlimit rl ;
-
- (void) getrlimit( RLIMIT_NOFILE, &rl ) ;
- return( rl.rlim_cur ) ;
-
- #else
-
- return( N_SIO_DESCRIPTORS ) ;
-
- #endif
- }
-
- /*
- * Expand the descriptor array (and if we use memory mapping the
- * memory mapping descriptors). We first expand the memory mapping
- * descriptors.
- * There is no problem if the expansion of the SIO descriptors fails
- * (i.e. there is no need to undo anything).
- */
- int Smorefds()
- {
- char *p ;
- int is_static ;
- unsigned new_size, old_size ;
- int n_fds = get_fd_limit() ;
-
- if ( n_fds <= n_descriptors )
- return( 0 ) ;
-
- #ifdef EVENTS
- old_size = n_descriptors * sizeof( events_s ) ;
- new_size = n_fds * sizeof( events_s ) ;
- is_static = ( __sio_events == static___sio_events ) ;
- p = expand( (char *)__sio_events, old_size, new_size, is_static ) ;
- if ( p == NULL )
- return( SIO_ERR ) ;
- __sio_events = (events_s *) p ;
-
- /*
- * Clear the codes field of the extra events structs.
- * We have to do this because a non-null codes field implies that
- * events recording is on for that fd
- */
- {
- int i ;
-
- for ( i = n_descriptors ; i < n_fds ; i++ )
- __sio_events[i].codes = NULL ;
- }
- #endif /* EVENTS */
-
- #ifdef HAS_MMAP
- old_size = n_descriptors * sizeof( mapd_s ) ;
- new_size = n_fds * sizeof( mapd_s ) ;
- is_static = ( mmap_descriptors == static_mapd_array ) ;
- p = expand( (char *)mmap_descriptors, old_size, new_size, is_static ) ;
- if ( p == NULL )
- return( SIO_ERR ) ;
- mmap_descriptors = (mapd_s *) p ;
- #endif /* HAS_MMAP */
-
- old_size = n_descriptors * sizeof( __sio_descriptor_t ) ;
- new_size = n_fds * sizeof( __sio_descriptor_t ) ;
- is_static = ( __sio_descriptors == static_descriptor_array ) ;
- p = expand( (char *)__sio_descriptors, old_size, new_size, is_static ) ;
- if ( p == NULL )
- return( SIO_ERR ) ;
- __sio_descriptors = (__sio_descriptor_t *) p ;
-
- n_descriptors = n_fds ;
- return( 0 ) ;
- }
-
-
- #ifdef EVENTS
-
- /*
- * Enable recording of events for the specified file descriptor
- */
- int __sio_enable_events( fd )
- int fd ;
- {
- char *p = malloc( EVENT_ENTRIES * sizeof( short ) ) ;
-
- if ( p == NULL )
- return( SIO_ERR ) ;
-
- __sio_events[ fd ].codes = (short *) p ;
- return( 0 ) ;
- }
-
-
- /*
- * Disable recording of events for the specified file descriptor
- */
- void __sio_disable_events( fd )
- int fd ;
- {
- if ( __sio_events[ fd ].codes != NULL )
- {
- free( (char *) __sio_events[ fd ].codes ) ;
- __sio_events[ fd ].codes = NULL ;
- }
- }
-
-
- /*
- * Move stored events to buf
- */
- int __sio_get_events( fd, buf, size )
- int fd ;
- char *buf ;
- int size ;
- {
- events_s *evp = &__sio_events[ fd ] ;
- int bufentries ;
- int range1, range2 ;
- int diff ;
- char *p ;
- int cc ;
- int cc_total ;
- int move_entries ;
-
- if ( evp->codes == NULL )
- return( 0 ) ;
-
- diff = evp->next - evp->start ;
- if ( diff == 0 )
- return( 0 ) ;
-
- if ( diff > 0 )
- {
- range1 = diff ;
- range2 = 0 ;
- }
- else
- {
- range1 = EVENT_ENTRIES - evp->start ;
- range2 = evp->next ;
- }
-
- bufentries = size / sizeof( short ) ;
- p = buf ;
- cc_total = 0 ;
-
- move_entries = MIN( range1, bufentries ) ;
- cc = move_entries * sizeof( short ) ;
- sio_memcopy( (char *) &evp->codes[ evp->start ], p, cc ) ;
- cc_total += cc ;
- p += cc ;
- bufentries -= range1 ;
- ADD( evp->start, move_entries ) ;
-
- if ( bufentries == 0 || range2 == 0 )
- return( cc_total ) ;
-
- move_entries = MIN( range2, bufentries ) ;
- cc = move_entries * sizeof( short ) ;
- sio_memcopy( (char *) &evp->codes[ evp->start ], p, cc ) ;
- cc_total += cc ;
- ADD( evp->start, move_entries ) ;
-
- return( cc_total ) ;
- }
-
- #endif /* EVENTS */
-
-
- /*
- * Simple function that prints the string s at stderr and then calls
- * exit
- */
- PRIVATE void terminate( s )
- char *s ;
- {
- (void) write( 2, s, strlen( s ) ) ;
- (void) abort() ;
- exit( 1 ) ; /* in case abort fails */
- }
-
-